#include "loadgraph.h"

void load_graph(char *fileName, int nline, int *vidmap){
    FILE *fp=NULL;
    int maxLineLen;
    char *line;

    fp = efopen(fileName, "r");
    
    /* plus '\n' and '\0' */
    maxLineLen = nline*(MAX_GID_LEN+1)+1;
    line = emalloc(maxLineLen*sizeof(*line));

    /* load two hashes */
    load_hash(fp, nline, line, maxLineLen);

    /* update global gN */
    gN = prune_graph(fp, nline, line, maxLineLen, vidmap); 
    first_shingle(fp, gN, line, maxLineLen, vidmap);

    free(line);
    fclose(fp);
}

void load_hash(FILE *fp, int nline, char *line, int lineLen){
    int i=0;
    char *header;

    while(fgets(line, lineLen, fp)){
        line[strlen(line)-1] = '\0';

        header = strtok(line, HEAD_DEL);   
        n2gidHash[i] = estrdup(header); /* i -> gid */
        hinsert(header, i); /* gid -> i */
        i++;
    }

    assert(i == nline);
}

int prune_graph(FILE *fp, int nline, char *line, int lineLen, int *vidmap){
    int i, j;
    int nDlts;
    int *adjList[nline];
    char *tmp;
    NODE *hp;
    NODE *min;
    int nl;

    rewind(fp);
    i = 0;
    hp = alloc_heap(nline);

    while(fgets(line, lineLen, fp)){
        line[strlen(line)-1] = '\0'; 

        nDlts = ndlts(line, LIST_DEL);

        /* one more for the end delimiter '-2' */
        adjList[i] = emalloc((nDlts+2)*sizeof(*adjList[i]));
        
        j = 0;
        strtok(line, HEAD_DEL);
        while((tmp=strtok(NULL, LIST_DEL))){
            adjList[i][j++] = hsearch(tmp);
        }
        
        /* mark the end */
        adjList[i][j] = ADJ_END;
        
        /* initialize the heap */
        hp[i].vid = i;
        hp[i].degree = nDlts+1;
        i++;
    }

    assert(i == nline);
    
    build_min_heap(hp, nline, vidmap);
    min = heap_min(hp, nline);

    nl = nline;
    while(min && min->degree < gS) {
        heap_extract_min(hp, &nl, adjList, vidmap);
        min = heap_min(hp, nl);
    } 


    /* free unused resource */
    free_heap(hp);
    free_adjList(adjList, nline); /* #nline != nl */
    
    return nl;
}

/* nl is #valid lines, and equals to updated gN */
int first_shingle(FILE *fp, int nl, char *line, int lineLen, int *vidmap){
    int sIndex;
    char *header, *tmp;
    int vertexId, olId;
    int outLinks[nl];
    int olCnt=0;

    rewind(fp);
    sIndex = 0;
    while(fgets(line, lineLen, fp)){
        line[strlen(line)-1] = '\0';

        header = strtok(line, HEAD_DEL); 
        vertexId = hsearch(header);
        
        /* vertex has been deleted */
        if(vidmap[vertexId] == PRUNED) continue;

        olCnt = 0;
        outLinks[olCnt++] = vertexId;
        while((tmp = strtok(NULL, LIST_DEL))){
            olId = hsearch(tmp);
            if(vidmap[olId] == PRUNED){
                continue; 
            }else{
                outLinks[olCnt++] = olId;
            }
        }
        /* lines becomes #vertices */
        assert(olCnt <= nl);
        
        shingle(vertexId, outLinks, olCnt, gFSgl, &sIndex);
    }

    assert(sIndex == nl*gC);

    return sIndex;
} 

void free_gid_hash(char **n2gidHash, int size){
    int i;
    for(i=0; i<size; i++){
        free(n2gidHash[i]);
    }
    free(n2gidHash);
}

/* sysmetric to malloc() in loadadj() */
void free_adjList(int *adjList[], int size){
    int i;
    for(i=0; i<size; i++){
        free(adjList[i]);
    }
}
